package org.openmrs.module.simplelabentry.web.controller.lab;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.EncounterType;
import org.openmrs.OrderType;
import org.openmrs.PatientIdentifierType;
import org.openmrs.Role;
import org.openmrs.api.ConceptService;
import org.openmrs.api.context.Context;
import org.openmrs.module.hospitalcore.BillingConstants;
import org.openmrs.module.hospitalcore.LabService;
import org.openmrs.module.hospitalcore.model.Lab;
import org.openmrs.module.simplelabentry.web.controller.propertyeditor.EncounterTypePropertyEditor;
import org.openmrs.module.simplelabentry.web.controller.propertyeditor.LabPropertyEditor;
import org.openmrs.module.simplelabentry.web.controller.propertyeditor.OrderTypePropertyEditor;
import org.openmrs.module.simplelabentry.web.controller.propertyeditor.PatientIdentifierTypePropertyEditor;
import org.openmrs.module.simplelabentry.web.controller.propertyeditor.RolePropertyEditor;
import org.springframework.beans.propertyeditors.CustomBooleanEditor;
import org.springframework.beans.propertyeditors.CustomCollectionEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/module/simplelabentry/lab.form")
public class LabFormController {
	
	private Log log = LogFactory.getLog(this.getClass());
	
	@InitBinder
	public void initBinder(WebDataBinder binder) {
		binder.registerCustomEditor(java.lang.Boolean.class, new CustomBooleanEditor(BillingConstants.TRUE,
		        BillingConstants.FALSE, true));
		binder.registerCustomEditor(Lab.class, new LabPropertyEditor());
		binder.registerCustomEditor(PatientIdentifierType.class, new PatientIdentifierTypePropertyEditor());
		binder.registerCustomEditor(Role.class, new RolePropertyEditor());
		binder.registerCustomEditor(OrderType.class, new OrderTypePropertyEditor());
		binder.registerCustomEditor(EncounterType.class, new EncounterTypePropertyEditor());
		binder.registerCustomEditor(Set.class, "investigationsToDisplay",new CustomCollectionEditor(Set.class){
			ConceptService conceptService = (ConceptService) Context.getConceptService();
			protected Object convertElement(Object element)
			    {
				  Integer conceptId = null;
			      if (element instanceof Integer)
			    	  conceptId = (Integer) element;
			      else if (element instanceof String)
			    	  conceptId = Integer.valueOf((String) element);
			      return conceptId != null ? conceptService.getConcept(conceptId) : null;
			    }
		});
		binder.registerCustomEditor(Set.class, "confidentialTestsToDisplay",new CustomCollectionEditor(Set.class){
			ConceptService conceptService = (ConceptService) Context.getConceptService();
			protected Object convertElement(Object element)
			    {
				  Integer conceptId = null;
			      if (element instanceof Integer)
			    	  conceptId = (Integer) element;
			      else if (element instanceof String)
			    	  conceptId = Integer.valueOf((String) element);
			      return conceptId != null ? conceptService.getConcept(conceptId) : null;
			    }
		});
	}
	
	@RequestMapping(method = RequestMethod.GET)
	public String firstView(@ModelAttribute("lab") Lab lab, @RequestParam(value="labId",required=false) Integer id, Model model) {
		if( id != null ){
			lab = Context.getService(LabService.class).getLabById(id);
			model.addAttribute(lab);
		}
//		model.addAttribute("orderTypes", Context.getOrderService().getAllOrderTypes());
		model.addAttribute("labEncounterTypes", Context.getEncounterService().getAllEncounterTypes());
		model.addAttribute("patientIdentifierTypes", Context.getPatientService().getAllPatientIdentifierTypes());
		List<Role> roles = getRoles();
		roles.add(lab.getRole());
		model.addAttribute("roles", roles);		
		return "/module/simplelabentry/lab/form";
	}
	
	@ModelAttribute("orderTypes")
	public List<OrderType> populateOrderTypes(){
		return Context.getOrderService().getAllOrderTypes();
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public String onSubmit(Lab lab, BindingResult bindingResult, HttpServletRequest request) {
		
		new LabValidator().validate(lab, bindingResult);
		if (bindingResult.hasErrors()) {
			return "/module/simplelabentry/lab/form";
		}
		LabService labService = Context.getService(LabService.class);
		if( lab.getRetired() ){
			lab.setRetiredDate(new Date());
		}
		labService.saveLab(lab);
		return "redirect:/module/simplelabentry/lab.list";
	}
	
	private List<Role> getRoles(){
		LabService labService = Context.getService(LabService.class);
		List<Role> roles = Context.getUserService().getAllRoles();
		List<Lab> labs = labService.getAllLab();
		
		// get all existing roles
		Set<Role> existingRoles = new HashSet<Role>();
		for(Lab l:labs){
			existingRoles.add(l.getRole());
		}
		
		// eliminate them from all roles list
		for(Role r:existingRoles){
			roles.remove(r);
		}
		
		// log the list of role		
		System.out.println("========== List of filtered roles =========");
		for(Role r:roles){
			System.out.println(r.getRole());
		}
		
		return roles;
	}
	

}
